#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from . import admin
from flask import render_template, redirect, url_for, flash, session, request, abort
from app.admin.forms import LoginForm, TagForm, MovieForm, PreviewForm, PwdForm, AuthForm, RoleForm, AdminForm
from app.models import Admin, Tag, Movie, Preview, User, Comment, Moviecol, Adminlog, Operatelog, Userlog, Auth, Role
from functools import wraps
from app import db, app
from werkzeug.utils import secure_filename
import os
import uuid  # 生成唯一字符串
import datetime  # 生成时间


# 定义上下文处理器,显示管理员首页登录时间


@admin.context_processor  # 上下文处理器，装饰器
def tpl_extra():
    data = dict(
        online_time=datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    )
    return data


# 定义登录权限的装饰器
def admin_login_req(f):
    @wraps(f)
    def decorated_fun(*args, **kwargs):
        if 'admin' not in session:
            return redirect(url_for("admin.login", next=request.url))
        return f(*args, **kwargs)

    return decorated_fun  # 返回装饰器


def admin_auth(f):  # 权限控制装饰器
    @wraps(f)
    def decorated_fun(*args, **kwargs):
        """
        admin_data = Admin.query.join(
            Role
        ).filter(
            Role.id == Admin.role_id,
            Admin.id == session['admin_id']
        ).first()
        auths = admin_data.role.auths
        auths = list(map(lambda v: int(v), auths.split(",")))
        auth_list = Auth.query.all()
        urls = [v.url for v in auth_list for val in auths if val == v.id]
        rule = request.url_rule
        print(urls)
        print(rule)
        if str(rule) not in urls:
            abort(404)
        """
        return f(*args, **kwargs)

    return decorated_fun


# 修改文件名称，
def change_filename(filename):
    fileinfo = os.path.splitext(filename)  # 文件分隔成后缀名 + 前缀
    # 有时间前缀和唯一字符串名称 + 文件后缀
    filename = datetime.datetime.now().strftime("%Y%m%d%H%M%S") + str(uuid.uuid4().hex) + fileinfo[-1]
    return filename


@admin.route("/")
@admin_login_req
@admin_auth
def index():
    return render_template("admin/index.html")


@admin.route('/login/', methods=["GET", "POST"])
def login():
    form = LoginForm()
    # 提交时,进行验证
    if form.validate_on_submit():
        data = form.data  # 获取表单信息
        admin = Admin.query.filter_by(name=data['account']).first()  # 查询出一条记录
        if not admin.check_pwd(data['pwd']):
            flash("密码错误")
            return redirect(url_for("admin.login"))
        session['admin'] = data['account']
        session['admin_id'] = admin.id
        # 记录管理员登录日志
        adminlog = Adminlog(
            admin_id=admin.id,
            #ip=request.remote_addr,
            ip=request.headers['X-Forwarded-For']
        )
        db.session.add(adminlog)
        db.session.commit()
        return redirect(request.args.get("next") or url_for("admin.index"))
    return render_template("admin/login.html", form=form)


@admin.route('/logout/')
@admin_auth
def logout():
    session.pop("admin", None)
    session.pop("admin_id", None)
    return redirect(url_for("admin.login"))


@admin.route('/modify_password/', methods=['GET', 'POST'])
@admin_login_req
@admin_auth
def modify_password():
    form = PwdForm()
    if form.validate_on_submit():
        data = form.data
        admin = Admin.query.filter_by(name=session['admin']).first()
        from werkzeug.security import generate_password_hash
        admin.pwd = generate_password_hash(data['new_pwd'])
        db.session.add(admin)
        db.session.commit()
        flash("修改成功，请重新登录", 'ok')
        return redirect(url_for("admin.logout"))
    return render_template("admin/modify_password.html", form=form)


@admin.route('/tag/list/<int:page>', methods=['GET'])
@admin_login_req
@admin_auth
def tag_list(page=None):
    if page is None:
        page = 1
    page_data = Tag.query.order_by(
        Tag.addtime.desc()
    ).paginate(page=page, per_page=10)
    return render_template("admin/tag_list.html", page_data=page_data)


@admin.route('/tag/add/', methods=['GET', 'POST'])
@admin_login_req
@admin_auth
def tag_add():
    form = TagForm()
    if form.validate_on_submit():
        data = form.data
        # 校验标签是否已存在
        tag = Tag.query.filter_by(name=data['name']).count()
        if tag == 1:
            flash("标签名称已存在", "error")
            return redirect(url_for('admin.tag_add'))
        # 插入数据库
        tag = Tag(
            name=data['name']
        )
        db.session.add(tag)
        db.session.commit()
        flash("标签提交成功", "ok")
        oplog = Operatelog(  # 记录操作日志
            admin_id=session['admin_id'],
            ip=request.remote_addr,
            reason="添加标签%s" % data['name']
        )
        db.session.add(oplog)
        db.session.commit()
        return redirect(url_for('admin.tag_add'))
    return render_template("admin/tag_add.html", form=form)


@admin.route('/tag/edit/<int:id>/', methods=['GET', 'POST'])
@admin_login_req
@admin_auth
def tag_edit(id):
    form = TagForm()
    tag = Tag.query.get_or_404(id)
    if form.validate_on_submit():
        data = form.data
        # 校验标签是否已存在
        tag_count = Tag.query.filter_by(name=data['name']).count()
        if tag.name != data['name'] and tag_count == 1:
            flash("标签名称已存在", "error")
            return redirect(url_for('admin.tag_edit', id=id))
        # 更新数据
        tag.name = data['name']
        db.session.add(tag)
        db.session.commit()
        flash("标签修改成功", "ok")
        return redirect(url_for('admin.tag_edit', id=id))
    return render_template("admin/tag_edit.html", form=form, tag=tag)


@admin.route('/tag/delete/<int:id>/', methods=['GET'])
@admin_login_req
@admin_auth
def tag_del(id=None):
    # tag = Tag.query.get(id)   通过主键查询
    tag = Tag.query.filter_by(id=id).first_or_404()
    db.session.delete(tag)
    db.session.commit()
    flash("标签删除成功", "ok")
    return redirect(url_for('admin.tag_list', page=1))


@admin.route('/movie/list/<int:page>', methods=['GET'])
@admin_login_req
@admin_auth
def movie_list(page=None):
    if page is None:
        page = 1
    page_data = Movie.query.join(Tag).filter(
        Tag.id == Movie.tag_id
    ).order_by(
        Movie.addtime.desc()
    ).paginate(page=page, per_page=20)
    return render_template("admin/movie_list.html", page_data=page_data)


@admin.route('/movie/add/', methods=['GET', 'POST'])
@admin_login_req
@admin_auth
def movie_add():
    form = MovieForm()
    if form.validate_on_submit():
        data = form.data
        # 获取上传文件数据
        file_url = secure_filename(form.url.data.filename)
        file_logo = secure_filename(form.logo.data.filename)
        if not os.path.exists(app.config['UP_DIR']):
            os.makedirs(app.config['UP_DIR'])
            os.chmod(app.config['UP_DIR'], 766)
        # 更改上传文件名
        url = change_filename(file_url)
        logo = change_filename(file_logo)
        # 保存上传数据
        form.url.data.save(app.config['UP_DIR'] + url)
        form.logo.data.save(app.config['UP_DIR'] + logo)
        movie = Movie(
            title=data['title'],
            url=url,
            info=data['info'],
            logo=logo,
            star=int(data['star']),
            playnum=0,
            commentnum=0,
            tag_id=int(data['tag_id']),
            area=data['area'],
            release_time=data['release_time'],
            length=data['length'],
        )
        # 数据库保存
        db.session.add(movie)
        db.session.commit()
        flash("添加成功", 'ok')
        return redirect(url_for('admin.movie_add', page=1))
    return render_template("admin/movie_add.html", form=form)


@admin.route('/movie/edit/<int:id>', methods=['GET', 'POST'])
@admin_login_req
@admin_auth
def movie_edit(id=None):
    form = MovieForm()
    # 不校验上传电影和封面
    form.url.validators = []
    form.logo.validators = []
    movie = Movie.query.get_or_404(int(id))
    if request.method == "GET":
        form.info.data = movie.info
        form.tag_id.data = movie.tag_id
        form.star.data = movie.star
    if form.validate_on_submit():
        data = form.data
        # 校验名称是否已存在
        movie_count = Movie.query.filter_by(title=data['title']).count()
        if movie.title != data['title'] and movie_count == 1:
            flash("名称已存在", "error")
            return redirect(url_for('admin.movie_edit', id=id))

        # 更新数据
        # todo 删除之前文件数据
        # 获取上传文件数据，更改了上传文件
        if not os.path.exists(app.config['UP_DIR']):
            os.makedirs(app.config['UP_DIR'])
            os.chmod(app.config['UP_DIR'], 766)

        if form.url.data != "":
            file_url = secure_filename(form.url.data.filename)
            movie.url = change_filename(file_url)
            form.url.data.save(app.config['UP_DIR'] + movie.url)

        if form.logo.data != "":
            file_logo = secure_filename(form.logo.data.filename)
            movie.logo = change_filename(file_logo)
            form.logo.data.save(app.config['UP_DIR'] + movie.logo)

        movie.title = data['title']
        movie.info = data['info']
        movie.star = data['star']
        movie.tag_id = data['tag_id']
        movie.release_time = data['release_time']
        movie.length = data['length']

        db.session.add(movie)
        db.session.commit()
        flash("修改成功", "ok")
        return redirect(url_for('admin.movie_edit', id=id))
    return render_template("admin/movie_edit.html", form=form, movie=movie)


@admin.route('/movie/delete/<int:id>', methods=['GET'])
@admin_login_req
@admin_auth
def movie_del(id=None):
    movie = Movie.query.filter_by(id=id).first_or_404()
    # todo 删除文件
    db.session.delete(movie)
    db.session.commit()
    flash("删除成功", "ok")
    return redirect(url_for('admin.movie_list', page=1))


@admin.route('/preview/list/<int:page>', methods=['GET'])
@admin_login_req
@admin_auth
def preview_list(page):
    if page is None:
        page = 1
    page_data = Preview.query.order_by(
        Preview.addtime.desc()
    ).paginate(page=page, per_page=10)
    return render_template("admin/preview_list.html", page_data=page_data)


@admin.route('/preview/add/', methods=['GET', 'POST'])
@admin_login_req
@admin_auth
def preview_add():
    form = PreviewForm()
    if form.validate_on_submit():
        data = form.data
        file_logo = secure_filename(form.logo.data.filename)
        logo = change_filename(file_logo)
        form.logo.data.save(app.config['UP_DIR'] + logo)
        preview = Preview(
            title=data['title'],
            logo=logo
        )
        db.session.add(preview)
        db.session.commit()
        flash("添加成功", 'ok')
    return render_template("admin/preview_add.html", form=form)


@admin.route('/preview/edit/<int:id>', methods=['GET', 'POST'])
@admin_login_req
@admin_auth
def preview_edit(id=None):
    form = PreviewForm()
    form.logo.validators = []
    preview = Preview.query.get_or_404(int(id))
    if form.validate_on_submit():
        data = form.data
        if form.logo.data != "":
            file_logo = secure_filename(form.logo.data.filename)
            preview.logo = change_filename(file_logo)
            form.logo.data.save(app.config['UP_DIR'] + preview.logo)
        preview.title = data['title']
        db.session.add(preview)
        db.session.commit()
        flash("修改成功", "ok")
        return redirect(url_for('admin.preview_edit', id=id))
    return render_template("admin/preview_edit.html", form=form, preview=preview)


@admin.route('/preview/delete/<int:id>', methods=['GET'])
@admin_login_req
@admin_auth
def preview_del(id=None):
    preview = Preview.query.get_or_404(id)
    db.session.delete(preview)
    db.session.commit()
    flash("删除成功", "ok")
    return redirect(url_for('admin.preview_list', page=1))


@admin.route('/user/list/<int:page>', methods=['GET'])
@admin_login_req
@admin_auth
def user_list(page):
    if page is None:
        page = 1
    page_data = User.query.order_by(
        User.addtime.desc()
    ).paginate(page=page, per_page=2)
    return render_template("admin/user_list.html", page_data=page_data)


@admin.route('/user/view/<int:id>')
@admin_login_req
@admin_auth
def user_view(id):
    user = User.query.get_or_404(int(id))
    return render_template("admin/user_view.html", user=user)


@admin.route('/user/delete/<int:id>', methods=['GET'])
@admin_login_req
@admin_auth
def user_del(id=None):
    user = User.query.get_or_404(id)
    db.session.delete(user)
    db.session.commit()
    flash("删除成功", "ok")
    return redirect(url_for('admin.user_list', page=1))


@admin.route('/collection/list/<int:page>', methods=['GET'])
@admin_login_req
@admin_auth
def collection_list(page):
    if page is None:
        page = 1
    page_data = Moviecol.query.join(
        Movie
    ).join(
        User
    ).filter(
        Moviecol.movie_id == Movie.id,
        Moviecol.user_id == User.id
    ).order_by(
        Moviecol.addtime.desc()
    ).paginate(page=page, per_page=10)
    return render_template("admin/collection_list.html", page_data=page_data)


@admin.route('/collection/delete/<int:id>', methods=['GET'])
@admin_login_req
@admin_auth
def collection_del(id=None):
    collection = Moviecol.query.get_or_404(id)
    db.session.delete(collection)
    db.session.commit()
    flash("删除成功", "ok")
    return redirect(url_for('admin.collection_list', page=1))


@admin.route('/comment/list/<int:page>', methods=['GET'])
@admin_login_req
@admin_auth
def comment_list(page):
    if page is None:
        page = 1
    page_data = Comment.query.join(
        Movie
    ).join(
        User
    ).filter(
        Comment.movie_id == Movie.id,
        Comment.user_id == User.id
    ).order_by(
        Comment.addtime.desc()
    ).paginate(page=page, per_page=10)
    return render_template("admin/comment_list.html", page_data=page_data)


@admin.route('/comment/delete/<int:id>', methods=['GET'])
@admin_login_req
@admin_auth
def comment_del(id=None):
    comment = Comment.query.get_or_404(id)
    db.session.delete(comment)
    db.session.commit()
    flash("删除成功", "ok")
    return redirect(url_for('admin.comment_list', page=1))


@admin.route('/operation/list/<int:page>', methods=['GET'])
@admin_login_req
@admin_auth
def operation_list(page):
    if page is None:
        page = 1
    page_data = Operatelog.query.join(
        Admin
    ).filter(
        Operatelog.admin_id == Admin.id,
    ).order_by(
        Operatelog.logintime.desc()
    ).paginate(page=page, per_page=10)
    return render_template("admin/operation_list.html", page_data=page_data)


@admin.route('/adminloginlog/list/<int:page>', methods=['GET'])
@admin_login_req
@admin_auth
def adminloginlog_list(page):
    if page is None:
        page = 1
    page_data = Adminlog.query.join(
        Admin
    ).filter(
        Adminlog.admin_id == Admin.id,
    ).order_by(
        Adminlog.logintime.desc()
    ).paginate(page=page, per_page=10)
    return render_template("admin/adminloginlog_list.html", page_data=page_data)


@admin.route('/userloginlog/list/<int:page>', methods=['GET'])
@admin_login_req
@admin_auth
def userloginlog_list(page):
    if page is None:
        page = 1
    page_data = Userlog.query.join(
        User
    ).filter(
        Userlog.user_id == User.id,
    ).order_by(
        Userlog.logintime.desc()
    ).paginate(page=page, per_page=10)
    return render_template("admin/userloginlog_list.html", page_data=page_data)


@admin.route('/auth/list/<int:page>', methods=['GET'])
@admin_login_req
@admin_auth
def auth_list(page):
    if page is None:
        page = 1
    page_data = Auth.query.order_by(
        Auth.addtime.desc()
    ).paginate(page=page, per_page=10)
    return render_template("admin/auth_list.html", page_data=page_data)


@admin.route('/auth/add/', methods=['GET', 'POST'])
@admin_login_req
@admin_auth
def auth_add():
    form = AuthForm()
    if form.validate_on_submit():
        data = form.data
        auth = Auth(
            name=data['name'],
            url=data['url']
        )
        db.session.add(auth)
        db.session.commit()
        flash("添加成功", "ok")
        return redirect(url_for('admin.auth_add'))
    return render_template("admin/auth_add.html", form=form)


@admin.route('/auth/edit/<int:id>', methods=['GET', 'POST'])
@admin_login_req
@admin_auth
def auth_edit(id):
    form = AuthForm()
    auth = Auth.query.get_or_404(id)
    if form.validate_on_submit():
        data = form.data
        # 更新数据
        auth.name = data['name']
        auth.url = data['url']
        db.session.add(auth)
        db.session.commit()
        flash("修改成功", "ok")
        return redirect(url_for('admin.auth_edit', id=id))
    return render_template("admin/auth_edit.html", form=form, auth=auth)


@admin.route('/auth/delete/<int:id>', methods=['GET'])
@admin_login_req
@admin_auth
def auth_del(id=None):
    auth = Auth.query.get_or_404(id)
    db.session.delete(auth)
    db.session.commit()
    flash("删除成功", "ok")
    return redirect(url_for('admin.auth_list', page=1))


@admin.route('/role/list/<int:page>', methods=['GET'])
@admin_login_req
@admin_auth
def role_list(page):
    if page is None:
        page = 1
    page_data = Role.query.order_by(
        Role.addtime.desc()
    ).paginate(page=page, per_page=10)
    return render_template("admin/role_list.html", page_data=page_data)


@admin.route('/role/add/', methods=['GET', 'POST'])
@admin_login_req
@admin_auth
def role_add():
    form = RoleForm()
    if form.validate_on_submit():
        data = form.data
        # print(data)           # 测试输出数据
        role = Role(
            name=data['name'],
            auths=",".join(map(lambda v: str(v), data['auths']))  # 数组拼接成字符串
        )
        db.session.add(role)
        db.session.commit()
        flash("添加成功", "ok")
        return redirect(url_for('admin.role_add'))
    return render_template("admin/role_add.html", form=form)


@admin.route('/role/delete/<int:id>', methods=['GET'])
@admin_login_req
@admin_auth
def role_del(id=None):
    role = Role.query.get_or_404(id)
    db.session.delete(role)
    db.session.commit()
    flash("删除成功", "ok")
    return redirect(url_for('admin.role_list', page=1))


@admin.route('/role/edit/<int:id>', methods=['GET', 'POST'])
@admin_login_req
@admin_auth
def role_edit(id):
    form = RoleForm()
    role = Role.query.get_or_404(id)
    if request.method == "GET":
        auths = role.auths
        form.auths.data = list(map(lambda v: int(v), auths.split(",")))
    if form.validate_on_submit():
        data = form.data
        # 更新数据
        role.name = data['name']
        role.auths = ",".join(map(lambda v: str(v), data['auths']))
        db.session.add(role)
        db.session.commit()
        flash("修改成功", "ok")
        return redirect(url_for('admin.role_edit', id=id))
    return render_template("admin/role_edit.html", form=form, role=role)


@admin.route('/admin/list/<int:page>', methods=['GET'])
@admin_login_req
@admin_auth
def admin_list(page):
    if page is None:
        page = 1
    page_data = Admin.query.join(
        Role
    ).filter(
        Role.id == Admin.role_id
    ).order_by(
        Role.addtime.desc()
    ).paginate(page=page, per_page=10)
    return render_template("admin/admin_list.html", page_data=page_data)


@admin.route('/admin/add/', methods=['GET', 'POST'])
@admin_login_req
@admin_auth
def admin_add():
    form = AdminForm()
    from werkzeug.security import generate_password_hash
    if form.validate_on_submit():
        data = form.data
        admin_data = Admin(
            name=data['name'],
            pwd=generate_password_hash(data['pwd']),
            role_id=data['role_id'],
            is_super=1
        )
        db.session.add(admin_data)
        db.session.commit()
        flash("添加成功", "ok")
        return redirect(url_for('admin.admin_add'))
    return render_template("admin/admin_add.html", form=form)
